﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web;

namespace Mozlite.WebUI.Mvc4
{
    /// <summary>
    /// HtmlHelper扩展方法类。
    /// </summary>
    public static class HtmlHelperExtensions
    {
        #region enum
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object attributes)
        {
            return helper.EnumDropdownListFor(expression, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            Cores.ForEach<TProperty>(m =>
            {
                items.Add(new SelectListItem { Text = helper.Local(m), Value = m.ToString() });
            });
            return helper.DropDownListFor(expression, items, attributes);
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="min">最小值。</param>
        /// <param name="max">最大值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, TProperty min, TProperty max, object attributes)
        {
            return helper.EnumDropdownListFor(expression, min, max, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="min">最小值。</param>
        /// <param name="max">最大值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, TProperty min, TProperty max, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            long lmin = min.To<long>();
            long lmax = max.To<long>();
            long current;
            Cores.ForEach<TProperty>(m =>
            {
                current = m.To<long>();
                if (current > lmin && current < lmax)
                    items.Add(new SelectListItem { Text = helper.Local(m), Value = m.ToString() });
            });
            return helper.DropDownListFor(expression, items, attributes);
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">表单名称。</param>
        /// <param name="value">枚举值，不能为空。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownList(this HtmlHelper helper, string name, object value, object attributes)
        {
            return helper.EnumDropdownList(name, value, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">表单名称。</param>
        /// <param name="value">枚举值，不能为空。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownList(this HtmlHelper helper, string name, object value, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            Type type = value.GetType();
            if(type.IsEnum)
            {
                foreach(var m in Enum.GetValues(type))
                {
                    items.Add(new SelectListItem { Text = helper.Local(m), Value = m.ToString() });
                }
            }
            return helper.DropDownList(name, items, attributes);
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">表单名称。</param>
        /// <param name="value">枚举值，不能为空。</param>
        /// <param name="min">最小值。</param>
        /// <param name="max">最大值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownList(this HtmlHelper helper, string name, object value, object min, object max, object attributes)
        {
            return helper.EnumDropdownList(name, value, min, max, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 枚举列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">表单名称。</param>
        /// <param name="value">枚举值，不能为空。</param>
        /// <param name="min">最小值。</param>
        /// <param name="max">最大值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString EnumDropdownList(this HtmlHelper helper, string name, object value, object min, object max, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            long lmin = min.To<long>();
            long lmax = max.To<long>();
            long current;
            Type type = value.GetType();
            if(type.IsEnum)
            {
                foreach(var m in Enum.GetValues(type))
                {
                    current = m.To<long>();
                    if(current > lmin && current < lmax)
                        items.Add(new SelectListItem { Text = helper.Local(m), Value = m.ToString() });
                }
            }
            return helper.DropDownList(name, items, attributes);
        }
        #endregion

        #region resources
        /// <summary>
        /// 获取当前语言资源字符串。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="key">资源键对象。</param>
        /// <returns>返回资源字符串。</returns>
        public static string Local(this HtmlHelper helper, object key)
        {
            var areaName = helper.ViewContext.GetAreaName();
            var resource = string.Empty;
            if (areaName != null)
                resource = Cores.GetGlobalResourceByKey(key, areaName);
            if(resource!=null)
                return resource;
            return Cores.GetGlobalResourceByKey(key);
        }

        /// <summary>
        /// 获取当前语言资源字符串。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="key">资源键对象。</param>
        /// <param name="args">格式化参数。</param>
        /// <returns>返回格式化后的资源字符串。</returns>
        public static string Local(this HtmlHelper helper, object key, params object[] args)
        {
            var areaName = helper.ViewContext.GetAreaName();
            var resource = string.Empty;
            if (areaName != null)
                resource = Cores.GetGlobalResourceByKey(key, areaName);
            if(resource == null)
                resource = Cores.GetGlobalResourceByKey(key);
            return resource.FormatWith(args);
        }
        #endregion

        #region label
        /// <summary>
        /// Label控件。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <returns>返回HTML字符串。</returns>
        public static MvcHtmlString LabelExFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
        {
            var name = ExpressionHelper.GetExpressionText(expression);
            return htmlHelper.LabelFor(expression, htmlHelper.Local("{0}_{1}".FormatWith(typeof(TModel).Name, name)), htmlAttributes);
        }
        #endregion

        #region helpers
        /// <summary>
        /// 控件扩展，添加验证。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="func">呈现的控件方法。</param>
        /// <param name="defaultCssClass">默认样式。</param>
        /// <param name="isValidControl">判断是否包含验证信息。</param>
        /// <returns>返回HTML字符串。</returns>
        internal static MvcHtmlString ControlFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IDictionary<string, object>, MvcHtmlString> func, string defaultCssClass, out bool isValidControl)
        {
            if (defaultCssClass == null)
                defaultCssClass = "k-textbox";
            isValidControl = false;
            if(htmlAttributes == null)
                return func(htmlHelper, expression, new RouteValueDictionary(new { @class = defaultCssClass }));
            var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            foreach(var key in attributes.Keys)
            {
                if(key.StartsWith("data-val-", StringComparison.OrdinalIgnoreCase))
                {
                    isValidControl = true;
                    break;
                }
            }
            if(!attributes.ContainsKey("class"))
                attributes.Add("class", defaultCssClass);
            if(isValidControl && !attributes.ContainsKey("data-val"))
                attributes.Add("data-val", "true");
            return func(htmlHelper, expression, attributes);
        }

        /// <summary>
        /// 控件扩展，添加验证。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">属性类型。</typeparam>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="func">呈现的控件方法。</param>
        /// <param name="isValidControl">判断是否包含验证信息。</param>
        /// <returns>返回HTML字符串。</returns>
        internal static MvcHtmlString ControlFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IDictionary<string, object>, MvcHtmlString> func, out bool isValidControl)
        {
            return htmlHelper.ControlFor(expression, htmlAttributes, func, null, out isValidControl);
        }
        
        /// <summary>
        /// 控件扩展，添加验证。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <typeparam name="name">名称。</typeparam>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="func">呈现的控件方法。</param>
        /// <param name="isValidControl">判断是否包含验证信息。</param>
        /// <returns>返回HTML字符串。</returns>
        internal static MvcHtmlString Control(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes, Func<HtmlHelper, string, object, IDictionary<string, object>, MvcHtmlString> func, out bool isValidControl)
        {
            return htmlHelper.Control(name, value, htmlAttributes, func, null, out isValidControl);
        }
        
        /// <summary>
        /// 控件扩展，添加验证。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <typeparam name="name">名称。</typeparam>
        /// <param name="value">值。</param>
        /// <param name="htmlAttributes">属性。</param>
        /// <param name="func">呈现的控件方法。</param>
        /// <param name="defaultCssClass">默认样式。</param>
        /// <param name="isValidControl">判断是否包含验证信息。</param>
        /// <returns>返回HTML字符串。</returns>
        internal static MvcHtmlString Control(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes, Func<HtmlHelper, string, object, IDictionary<string, object>, MvcHtmlString> func, string defaultCssClass, out bool isValidControl)
        {
            if (defaultCssClass == null)
                defaultCssClass = "k-textbox";
            isValidControl = false;
            if(htmlAttributes == null)
                return func(htmlHelper, name, value, new RouteValueDictionary(new { @class = defaultCssClass }));
            var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            foreach(var key in attributes.Keys)
            {
                if(key.StartsWith("data-val-", StringComparison.OrdinalIgnoreCase))
                {
                    isValidControl = true;
                    break;
                }
            }
            if(!attributes.ContainsKey("class"))
                attributes.Add("class", defaultCssClass);
            if(isValidControl && !attributes.ContainsKey("data-val"))
                attributes.Add("data-val", "true");
            return func(htmlHelper, name, value, attributes);
        }
        #endregion

        #region validcode
        /// <summary>
        /// 验证码输入框。
        /// </summary>
        /// <param name="htmlHelper">HTML辅助实例对象。</param>
        /// <param name="name">输入框名称。</param>
        /// <param name="key">验证唯一键。</param>
        /// <param name="width">宽。</param>
        /// <param name="height">高。</param>
        /// <param name="htmlAttributes">HTML属性实例对象。</param>
        /// <returns>返回HTML代码。</returns>
        public static MvcHtmlString ValidCodeBox(this HtmlHelper htmlHelper, string name, string key, int width, int height, object htmlAttributes = null)
        {
            TagBuilder tag = new TagBuilder("INPUT");
            tag.Attributes.Add("type", "text");
            tag.Attributes.Add("name", name);
            tag.Attributes.Add("id", name);
            if (htmlAttributes != null)
                tag.MergeAttributes<string, object>(new RouteValueDictionary(htmlAttributes));
            var url = SiteUrls.GetValidCodeUrl(key, width, height);
            var img = new TagBuilder("IMG");
            img.Attributes.Add("src", url);
            img.Attributes.Add("class", "validcode");
            img.Attributes.Add("alt", htmlHelper.Local("ValidCode"));
            img.Attributes.Add("title", htmlHelper.Local("ValidCode_Refresh"));
            img.Attributes.Add("onclick", "this.src='{0}?ran=' + Math.random();".FormatWith(url));
            return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing) + img.ToString(TagRenderMode.SelfClosing));
        }
        #endregion

        #region languages
        /// <summary>
        /// 区域语言列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString CultureDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object attributes)
        {
            return helper.CultureDropdownListFor(expression, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 区域语言列表。
        /// </summary>
        /// <typeparam name="TModel">模型类型。</typeparam>
        /// <typeparam name="TProperty">枚举类型。</typeparam>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="expression">表达式。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString CultureDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            Globals.Lanaguages.ForEach(language =>
            {
                items.Add(new SelectListItem { Text = helper.Local(language.Replace('-', '_')), Value = language });
            });
            return helper.DropDownListFor(expression, items, attributes);
        }
        /// <summary>
        /// 区域语言列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString CultureDropdownList(this HtmlHelper helper, string name, object value, object attributes)
        {
            return helper.CultureDropdownList(name, value, new RouteValueDictionary(attributes));
        }
        /// <summary>
        /// 区域语言列表。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="name">名称。</param>
        /// <param name="value">值。</param>
        /// <param name="attributes">属性。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString CultureDropdownList(this HtmlHelper helper, string name, object value, IDictionary<string, object> attributes = null)
        {
            List<SelectListItem> items = new List<SelectListItem>();
            Globals.Lanaguages.ForEach(language =>
            {
                items.Add(new SelectListItem { Text = helper.Local(language.Replace('-', '_')), Value = language, Selected = language.IsCaseInsensitiveEqual(value as string) });
            });
            return helper.DropDownList(name, items, attributes);
        }
        #endregion

        #region editor
        /// <summary>
        /// 应用编辑器。
        /// </summary>
        /// <param name="helper">Html辅助类实例对象。</param>
        /// <param name="skin">样式类型。</param>
        /// <returns>返回呈现的字符串。</returns>
        public static MvcHtmlString KindEditor(this HtmlHelper helper, KindEditorSkin skin = KindEditorSkin.Default)
        {
            return MvcHtmlString.Create("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" /><script src=\"{1}\" type=\"text/javascript\"></script><script src=\"{2}\" type=\"text/javascript\"></script>".FormatWith(
            Cores.GetUtil("kindeditor", "themes", skin, skin + ".css"),
            Cores.GetUtil("kindeditor", "kindeditor-min.js"),
            Cores.GetUtil("kindeditor", "lang", AppContext.Current.CultureName + ".js")));
        }
        #endregion
    }
}
